import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import com.db4o.Db4o;
import com.db4o.Db4oEmbedded;
import com.db4o.ObjectContainer;
import com.db4o.query.Predicate;

public class Location {
	PopulateDatabase p;
	Station source, destination, temp;
	Node node;
	/* Hashmap for vertices because we had make 14 as 2 etc */
	HashMap<Integer, Integer> hashMap;
	Dijkstra dijkstra;
	ArrayList<Integer> queue, finishedVertices;
	/* The list of vertices which have been dequeued */
	ArrayList<Integer> finishedVertices2;
	ObjectContainer db;
	
	public Location() {
		try {
			p = new PopulateDatabase();
		} catch (Exception e) {
		}
		hashMap = new HashMap<Integer, Integer>();
		try {
			dijkstra = new Dijkstra();
		} catch (Exception e) {
		}
		queue = new ArrayList<Integer>();
		finishedVertices = new ArrayList<Integer>();
		finishedVertices2 = new ArrayList<Integer>();
	}
	
	public void openDatabase(){
		db=Db4oEmbedded.openFile(Db4oEmbedded
				.newConfiguration(), "Routing Management System");
	}
	
	public void closeDatabase(){
		db.close();
	}
	
	Station retrieveStationObject(final int stationCode) {
		/* Code to retrieve a particular object */
	@SuppressWarnings("serial")
	List<Station> station = db.query(new Predicate<Station>() {
		public boolean match(Station station) {
			return station.getStationCode() == stationCode;
		}
	});
	Station st = station.get(0);
	return st;
}
	
	Track retrieveTrackObject(final int station1, final int station2) {
		@SuppressWarnings("serial")
		List<Track> track1 = db.query(new Predicate<Track>() {
			public boolean match(Track track) {
				return track.getNextStation() == station1
						&& track.getPrevStation() == station2;
			}
		});
		if (track1.size() != 0) {
			Track tr = track1.get(0);
			return tr;
		} else
			return null;
	}

	/* Enqueue and Dequeue functions for Breadth First Search */
	public void enqueue(int item) {

		if (binarySearch(queue, item) && binarySearch(finishedVertices, item)) {
			queue.add(item);
		}
	}

	public int dequeue() {
		int item = queue.get(0);
		finishedVertices.add(item);
		queue.remove(0);
		return item;
	}

	boolean binarySearch(ArrayList<Integer> queue, int toSearch) {
		int begin, end, midPoint;
		begin = 0;
		end = queue.size() - 1;
		while (begin <= end) {
			midPoint = (begin + end) / 2;
			if (queue.get(midPoint) == toSearch) {
				return false;
			} else if (queue.get(midPoint) < toSearch) {
				begin = midPoint + 1;
			} else {
				end = midPoint - 1;
			}
		}
		return true;
	}
	
	

	public void displayHashMap() {
		for (Integer i : hashMap.keySet()) {
//			System.out.println(i + " " + hashMap.get(i));
		}
	}

	public ArrayList<Integer> createGraph(GUIPanel guiPanel,int sourceStationCode,
			int destStationCode) {
		openDatabase();
		
		@SuppressWarnings("unused")
		ArrayList<Integer> stations = new ArrayList<Integer>();
		int counter = 1, item = 0, firstTime = 0, lock = 0, t = 0, q = 0, x = 0, f = 1;
		// double lat_difference = lat2 - lat1;
		// double long_difference = long2 - long1;
		/*
		 * Creating an object of Populatedatabase so that we can access its
		 * retrieve station method
		 */
		try{
		source = guiPanel.getStationGraph().get(sourceStationCode);//p.retrieveStationObject(sourceStationCode);
		}catch(Exception e){
			return null;
		}
		destination = guiPanel.getStationGraph().get(destStationCode);//p.retrieveStationObject(destStationCode);
		/* Adding the source station code to the queue */
		queue.add(sourceStationCode);
		/* Means Destination is in NE */
		// if (lat_difference > 0 && long_difference > 0) {
		hashMap.put(counter, sourceStationCode);
		node = new Node(counter);
		/* Dequeuing the vertex */
		while (!queue.isEmpty()) {
			if (firstTime == 0) {
				/* For the first time we have to start from the source */
				temp = source;
				firstTime++;
				item = dequeue();
				finishedVertices2.add(item);
//				System.out.println("item " + item);
//				System.out.println("f " + f++);
				/* Dequeuing the first station */
				// System.out.println(dequeue() + " " +
				// temp.getStationName());
			} else {
//				System.out.println("f " + f++);
				/* Dequeuing the queue to work on the latest station */
				item = dequeue();
//				System.out.println("item " + item);
				/* Stations that have been traversed */
				if (finishedVertices2.contains(item)) {
					continue;
				}
//				System.out.println("item " + item);
				finishedVertices2.add(item);
				/* Retrieving the latest station */
				temp = guiPanel.getStationGraph().get(item);//p.retrieveStationObject(item);

				// System.out.println(item + " " + temp.getStationName());
				/* Mapping the station code to a number */
				if (!hashMap.containsValue(item)) {
					/* Incrementing the counter every time for the hashmap */
					counter++;
					hashMap.put(counter, item);
					node = new Node(counter);
				} else {
					/* Alternate code */
					/* hashMap.put(counter, item); */
					/* Creating the node for the dijkstra's graph */
					int j = 0;
					for (Integer i : hashMap.keySet()) {
						if (item == hashMap.get(i)) {
							j = i;
							break;
						}
					}

					node = new Node(j);
				}

			}
			/*
			 * Traversing through all the vertices of the adjacency list i.e
			 * breadth first traversal
			 */
//			System.out.println(temp.getStationCode() + ":"
//					+ temp.getStationName());
			for (Integer i : temp.getAdjacentStations()) {
//				System.out.print(guiPanel.getStationGraph().get(i).getStationName()
//						+ " ");
				/* The moment the destination node comes we will lock it */
				if (i == destStationCode) {
					/*
					 * Enqueuing the destination station so that that appears in
					 * the hash map
					 */
					enqueue(i);
					lock = 1;
				}
				/*
				 * Checking if it is located in the NE then add all those
				 * adjacent stations
				 */
				// if (checkStationLocation(i, lat1, long1, lat_difference,
				// long_difference)) {
				if (guiPanel.getStationGraph().get(i).getState()
						.equals("Andhra Pradesh")|| guiPanel.getStationGraph().get(i).getState()
						.equals("Karnataka")) {
					/*
					 * Here adjacent nodes may be 31 41 etc We will anyway be
					 * mapping them with a hash map
					 */
					if (!hashMap.containsValue(i)) {
						counter++;
						hashMap.put(counter, i);
						node.getAdjacentLinks().add(counter);
					} else {
						for (Integer u : hashMap.keySet()) {
							x = hashMap.get(u);
							if (x == i)
								q = u;
						}
						node.getAdjacentLinks().add(q);
					}

					node.getWeights().add(
							retrieveTrackObject(i, temp.getStationCode())
									.getLengthOfTrack());
					/* Enqueue each vertex as it is a breadth first search */
					if (lock == 0)
						enqueue(i);
				}
			}
//			System.out.println("\n");
			/* Adding that node to the dijkstra's Graph */
			t++;
			// displayNodeDetails();
			/*
			 * if(t==8){ node.getAdjacentLinks().remove(1);
			 * node.getWeights().remove(1); }
			 */
			dijkstra.getGraphArrayList().add(node);
		}
//		System.out.println("Graph");
//		dijkstra.displayGraph();
//		System.out.println("HashMap");
//		displayHashMap();
//		System.out.println("The total number of nodes added are " + t);
		dijkstra.dijkstra_Algorithm(t, 1);
//		dijkstra.showShortestpath();
		/* Function to display the shortest path */
		dijkstra.shortestPath(t);
		closeDatabase();
		return dijkstra.displayPath(this, t);
	}

	public ArrayList<Integer> createGraph1(GUIPanel1 guiPanel,int sourceStationCode,
			int destStationCode) {
		openDatabase();
		
		@SuppressWarnings("unused")
		ArrayList<Integer> stations = new ArrayList<Integer>();
		int counter = 1, item = 0, firstTime = 0, lock = 0, t = 0, q = 0, x = 0, f = 1;
		// double lat_difference = lat2 - lat1;
		// double long_difference = long2 - long1;
		/*
		 * Creating an object of Populatedatabase so that we can access its
		 * retrieve station method
		 */
		try{
		source = guiPanel.getStationGraph().get(sourceStationCode);//p.retrieveStationObject(sourceStationCode);
		}catch(Exception e){
			return null;
		}
		destination = guiPanel.getStationGraph().get(destStationCode);//p.retrieveStationObject(destStationCode);
		/* Adding the source station code to the queue */
		queue.add(sourceStationCode);
		/* Means Destination is in NE */
		// if (lat_difference > 0 && long_difference > 0) {
		hashMap.put(counter, sourceStationCode);
		node = new Node(counter);
		/* Dequeuing the vertex */
		while (!queue.isEmpty()) {
			if (firstTime == 0) {
				/* For the first time we have to start from the source */
				temp = source;
				firstTime++;
				item = dequeue();
				finishedVertices2.add(item);
//				System.out.println("item " + item);
//				System.out.println("f " + f++);
				/* Dequeuing the first station */
				// System.out.println(dequeue() + " " +
				// temp.getStationName());
			} else {
//				System.out.println("f " + f++);
				/* Dequeuing the queue to work on the latest station */
				item = dequeue();
//				System.out.println("item " + item);
				/* Stations that have been traversed */
				if (finishedVertices2.contains(item)) {
					continue;
				}
//				System.out.println("item " + item);
				finishedVertices2.add(item);
				/* Retrieving the latest station */
				temp = guiPanel.getStationGraph().get(item);//p.retrieveStationObject(item);

				// System.out.println(item + " " + temp.getStationName());
				/* Mapping the station code to a number */
				if (!hashMap.containsValue(item)) {
					/* Incrementing the counter every time for the hashmap */
					counter++;
					hashMap.put(counter, item);
					node = new Node(counter);
				} else {
					/* Alternate code */
					/* hashMap.put(counter, item); */
					/* Creating the node for the dijkstra's graph */
					int j = 0;
					for (Integer i : hashMap.keySet()) {
						if (item == hashMap.get(i)) {
							j = i;
							break;
						}
					}

					node = new Node(j);
				}

			}
			/*
			 * Traversing through all the vertices of the adjacency list i.e
			 * breadth first traversal
			 */
//			System.out.println(temp.getStationCode() + ":"
//					+ temp.getStationName());
			for (Integer i : temp.getAdjacentStations()) {
//				System.out.print(guiPanel.getStationGraph().get(i).getStationName()
//						+ " ");
				/* The moment the destination node comes we will lock it */
				if (i == destStationCode) {
					/*
					 * Enqueuing the destination station so that that appears in
					 * the hash map
					 */
					enqueue(i);
					lock = 1;
				}
				/*
				 * Checking if it is located in the NE then add all those
				 * adjacent stations
				 */
				// if (checkStationLocation(i, lat1, long1, lat_difference,
				// long_difference)) {
				if (guiPanel.getStationGraph().get(i).getState()
						.equals("Andhra Pradesh")|| guiPanel.getStationGraph().get(i).getState()
						.equals("Karnataka")) {
					/*
					 * Here adjacent nodes may be 31 41 etc We will anyway be
					 * mapping them with a hash map
					 */
					if (!hashMap.containsValue(i)) {
						counter++;
						hashMap.put(counter, i);
						node.getAdjacentLinks().add(counter);
					} else {
						for (Integer u : hashMap.keySet()) {
							x = hashMap.get(u);
							if (x == i)
								q = u;
						}
						node.getAdjacentLinks().add(q);
					}

					node.getWeights().add(
							retrieveTrackObject(i, temp.getStationCode())
									.getLengthOfTrack());
					/* Enqueue each vertex as it is a breadth first search */
					if (lock == 0)
						enqueue(i);
				}
			}
//			System.out.println("\n");
			/* Adding that node to the dijkstra's Graph */
			t++;
			// displayNodeDetails();
			/*
			 * if(t==8){ node.getAdjacentLinks().remove(1);
			 * node.getWeights().remove(1); }
			 */
			dijkstra.getGraphArrayList().add(node);
		}
//		System.out.println("Graph");
//		dijkstra.displayGraph();
//		System.out.println("HashMap");
//		displayHashMap();
//		System.out.println("The total number of nodes added are " + t);
		dijkstra.dijkstra_Algorithm(t, 1);
//		dijkstra.showShortestpath();
		/* Function to display the shortest path */
		dijkstra.shortestPath(t);
		closeDatabase();
		return dijkstra.displayPath(this, t);
	}

	/*
	 * Means Destination is in NW else if (lat_difference > 0 && long_difference
	 * < 0) {
	 * 
	 * }/* Means Destination is in SE else if (lat_difference < 0 &&
	 * long_difference > 0) {
	 * 
	 * }/* Means Destination is in SW else if (lat_difference < 0 &&
	 * long_difference < 0) {
	 * 
	 * }
	 */
	// }

	public double computeDistance(double d1, double d2) {
		return Math.sqrt(Math.pow(d1, 2) + Math.pow(d2, 2));
	}

	public boolean checkStationLocation(int i, double lat1, double long1,
			double lat_difference, double long_difference) {
		/*
		 * double stationLatitude, stationLongitude; /* latdistance and
		 * longdistance re actual source and destination
		 */
		/*
		 * double sourceDestinationRadius = computeDistance(lat_difference,
		 * long_difference);
		 */
		/*
		 * stationlatitude and longitude are adjacent stations latitude and
		 * longitude because they have to be checked
		 */
		/*
		 * stationLatitude = p.retrieveStationObject(i).getLatitude();
		 * stationLongitude = p.retrieveStationObject(i).getLongitude(); double
		 * adjacentStationRadius = computeDistance(stationLatitude - lat1,
		 * stationLongitude - long1);
		 */

		if (retrieveStationObject(i).getLatitude() > lat1
				&& retrieveStationObject(i).getLongitude() > long1)
			return true;

		/*
		 * if (adjacentStationRadius < sourceDestinationRadius) return true;
		 */
		return false;
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Location l = new Location();
		try {
			// @SuppressWarnings("resource")
			// BufferedReader br = new BufferedReader(new FileReader(
			// "input2"));

			// @SuppressWarnings("unused")
			// int a1 = Integer.parseInt(br.readLine());
			// double a2 = Double.parseDouble(br.readLine());
			// double a3 = Double.parseDouble(br.readLine());
			// @SuppressWarnings("unused")
			// int a4 = Integer.parseInt(br.readLine());
			// double a5 = Double.parseDouble(br.readLine());
			// double a6 = Double.parseDouble(br.readLine());

			/*
			 * Insert source station and destination station code along with
			 * their latitude and longitude
			 */
			ArrayList<Integer> stations=l.createGraph(null,7, 25);
//			System.out.print("--------------------------------------------------------\n\n\n");
//			for(Integer i:stations)
//				System.out.print(i+" ");
		} catch (Exception e) {

		}
	}
}
